use std::ffi::c_void;

// Assuming these functions are defined elsewhere in your Rust codebase
extern "C" {
    fn pointer_hash(location: *const c_void) -> u32;
    fn int_hash(value: *const i32) -> u32;
    fn string_hash(string: *const u8) -> u32;
    fn string_nocase_hash(string: *const u8) -> u32;
}

const NUM_TEST_VALUES: usize = 200;

fn test_pointer_hash() {
    let mut array = [0; NUM_TEST_VALUES];

    for i in 0..NUM_TEST_VALUES {
        for j in (i + 1)..NUM_TEST_VALUES {
            assert_ne!(unsafe { pointer_hash(&array[i] as *const _ as *const c_void) },
                       unsafe { pointer_hash(&array[j] as *const _ as *const c_void) });
        }
    }
}

fn test_int_hash() {
    let mut array = [0; NUM_TEST_VALUES];

    for i in 0..NUM_TEST_VALUES {
        array[i] = i as i32;
    }

    for i in 0..NUM_TEST_VALUES {
        for j in (i + 1)..NUM_TEST_VALUES {
            assert_ne!(unsafe { int_hash(&array[i]) }, unsafe { int_hash(&array[j]) });
        }
    }

    let i = 5000;
    let j = 5000;

    assert_eq!(unsafe { int_hash(&i) }, unsafe { int_hash(&j) });
}

fn test_string_hash() {
    let test1 = b"this is a test\0";
    let test2 = b"this is a tesu\0";
    let test3 = b"this is a test \0";
    let test4 = b"this is a test\0";
    let test5 = b"This is a test\0";

    assert_ne!(unsafe { string_hash(test1.as_ptr()) }, unsafe { string_hash(test2.as_ptr()) });
    assert_ne!(unsafe { string_hash(test1.as_ptr()) }, unsafe { string_hash(test3.as_ptr()) });
    assert_ne!(unsafe { string_hash(test1.as_ptr()) }, unsafe { string_hash(test5.as_ptr()) });
    assert_eq!(unsafe { string_hash(test1.as_ptr()) }, unsafe { string_hash(test4.as_ptr()) });
}

fn test_string_nocase_hash() {
    let test1 = b"this is a test\0";
    let test2 = b"this is a tesu\0";
    let test3 = b"this is a test \0";
    let test4 = b"this is a test\0";
    let test5 = b"This is a test\0";

    assert_ne!(unsafe { string_nocase_hash(test1.as_ptr()) }, unsafe { string_nocase_hash(test2.as_ptr()) });
    assert_ne!(unsafe { string_nocase_hash(test1.as_ptr()) }, unsafe { string_nocase_hash(test3.as_ptr()) });
    assert_eq!(unsafe { string_nocase_hash(test1.as_ptr()) }, unsafe { string_nocase_hash(test5.as_ptr()) });
    assert_eq!(unsafe { string_nocase_hash(test1.as_ptr()) }, unsafe { string_nocase_hash(test4.as_ptr()) });
}

type UnitTestFunction = fn();

static TESTS: &[Option<UnitTestFunction>] = &[
    Some(test_pointer_hash),
    Some(test_int_hash),
    Some(test_string_hash),
    Some(test_string_nocase_hash),
    None,
];

fn run_tests(tests: &[Option<UnitTestFunction>]) {
    for test in tests.iter() {
        if let Some(t) = test {
            t();
        } else {
            break;
        }
    }
}

fn main() {
    run_tests(TESTS);
}
